//! This is a simple example of 
//! 1. form/GET/POST
//!  - leptos invoke axum‘s get—handler, and post—handler.
//! 2. async with Transition
//! 案例表明：
//! a) 程序启动的时候，各页面极其涉及的异步也都会被执行，用于页面构造。
//! b) 点击链接访问此页面时，只有Transition/Suspense 内的异步才会正确执行。
//! 
//! 
use http::header::{HOST, SERVER};
use leptos::*;
use leptos_dom::helpers::location;
use serde::*;
use chrono::prelude::*;
use leptos::{html::Input, IntoView };
use svg::view;
use thiserror::Error;
use anyhow::{bail, Result};
use reqwest::header::HeaderMap;

use gloo_net::http::*;

use reqwasm::http::Request;
use leptos_meta::*;
use leptos_router::*;
use common::Task;
// use leptos_axum::extract_with_state;


#[derive(Debug, Clone)]
struct ValueSetter(String);

#[component]
pub fn AxumFormView() -> impl IntoView {
    


    let qry = use_query_map();
    let query = move || qry.get().get("query").cloned().unwrap_or_default();
    // let s = format!("{}", query());
    let (sdata, set_sdata) = create_signal("".to_owned());

    let async_with_tran = create_resource(
        move || sdata.get(),
        // 每次 `count` 发生变化时，这都会运行
        |value| async move {            
            let s = get_axum_data(&value).await.unwrap_or(vec![]);                         
            s
        },
    );  
    /*    
    let async_no_tran   = create_resource(
        move || sdata.get(),
        // 每次 `count` 发生变化时，这都会运行
        |value| async move {            
            let s = get_axum_data("No-Transition", "name").await.unwrap_or(vec![]);                          
            s
        },
    ); */     

    view! {        
        <Title text="Axum Get/Post"/>       
        <div>
            <label>
                "axum get data: " { move || {
                    let s = query();
                    if  s.len()> 0 {
                        set_sdata.set(s.to_owned());
                        s                        
                    }else {
                        "no query".to_owned()
                    }
                    }
                }
            </label>
            <div>
                <Transition fallback=move || view! { <div>loading...</div>}>
                {
                    move || {
                        let sdata =  if let Some(s) = async_with_tran.get(){
                            s
                        }else {
                            vec![]
                        };
                        view! {
                            <p align="left">"You want : " 
                            
                            {
                                sdata.into_iter()
                                .map(|n| view! { <li>{n.id} ": " {n.name}, {n.timestamp}</li>})
                                .collect::<Vec<_>>()
                            } 
                            
                            </p>
                        }                        
                    }                    
                }
                </Transition>              
            </div>       
            <br/>
       
        <label>
            "axum get data, NO (Transition, Suspense) "
        </label>
        <div>
            <span style="color:red;"> "more error in console! so disable following code， async should use <Transition> !"</span>
            {                
                /* 
                move || {
                    let tdata =  if let Some(s) = async_no_tran.get(){
                        s
                    }else {
                        vec![]
                    };
                    view! {
                        <p>"You want " {
                            tdata.into_iter()
                                .map(|n| view! { <li>{n.name}, {n.timestamp}</li>})
                                .collect::<Vec<_>>()
                        
                        } </p>
                    }
                } */
            }        
        </div><br/>

        <PostAxumForm/>  
        <br/>         
       
        </div>
    }    
}


#[component]
pub fn PostAxumForm() -> impl IntoView {    
    // let spreadable = style(("background-color", "AliceBlue"));
    view! {
        <div>
            <label>
                "this is a form post example with axum"                
            </label><br/>
            <Form method="POST" action="/axum/post_task">
            <input type="text" name="name" value="hello"  /><br/>
            <input type="text" name="count" value="9"  /><br/><br/>
            <button type="submit">"submit"</button>
            </Form>            
        </div>
    }    
}
///get data from server by axum-get handler
///-  在浏览器端，通过reqwest get，直接访问axum server，获取数据（而不是编写 #[server] fn）
///-  从效率角度讲，应该是基本相同的；
///-  通过leptos的server宏实现数据获取，最大的问题是，目前无法获得axum的State，从而获得dbpool；
///-  后续如果找到解决办法，编写server_fn是最优选择！
pub async fn get_axum_data(query: &str) -> Result<Vec<Task>> {    
/*
// https://lib.rs/crates/gloo-net
// gloo_net, WASM应用程序的HTTP请求库。它为web_sys fetch和WebSocket API提供了惯用的Rust绑定。
// 使用gloo_net，有效的解决了服务器地址的问题;;)

use std::collections::HashMap;
use gloo_net::http::Request;

let slice_params = [("key", "value")];
let vec_params = vec![("a", "3"), ("b", "4")];
let mut map_params: HashMap<&'static str, &'static str> = HashMap::new();
map_params.insert("key", "another_value");

let r = Request::get("/search")
    .query(slice_params)
    .query(vec_params)
    .query(map_params);
// Result URL: /search?key=value&a=3&b=4&key=another_value   


    logging::log!("{},{}", who, query);
    let api = format!("/axum/get_task?query={}", query);         
    let r:Vec<Task> = Request::get(&api)
        .send()
        .await?
        .json().await?;
    */ 

    use http::request::Parts;
    // this is just an example of how to access server context injected in the handlers
    let req_parts = use_context::<Parts>();

    let server_host = if let Some(req_parts) = req_parts {
        // println!("Uri = {:?}", req_parts.uri);        
        // logging::log!("{:#?}", req_parts);
        req_parts.headers.get("host").unwrap().clone()
    }else{
        bail!("no context");
    };

    let api = format!("http://{}/axum/get_task?query={}", server_host.to_str().unwrap(), query);        
    // logging::log!("api = {:#?}", api);

    let client = reqwest::Client::new();
    let headers = HeaderMap::new();
    //headers.insert("Authorization", "Bearer xman".parse()?);
    // headers.insert("Content-Type", "application/json; charset=utf-8".parse()?);
    let r:Vec<Task> = client    
        .get(&api)
        .headers(headers)        
        .send()
        .await?
        .json()
        .await?;
    
    // logging::log!("get_axum_data: {:?}", r  );    
    return std::result::Result::Ok(r);
}
   